package cn.shopifymall.camunda717.api;

import cn.shopifymall.camunda717.entity.WkflTaskEntity;
import cn.shopifymall.camunda717.service.WkflTaskService;
import cn.shopifymall.camunda717.service.WorkflowService;
import cn.shopifymall.camunda717.util.Result;
import cn.shopifymall.camunda717.vo.OperationVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.apache.commons.lang3.StringUtils;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.runtime.ProcessInstanceModificationBuilder;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.engine.variable.Variables;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.FlowNode;
import org.camunda.bpm.model.xml.instance.DomElement;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 孤风雪影
 * @Email gitee.com/efairy520
 * @Date 2024/5/11 18:20
 * @Version 1.0
 */
@RestController("/api")
public class ProcessApi {

    public static final ThreadLocal<OperationVo> operationVoHolder = new ThreadLocal<>();

    @Autowired
    private IdentityService identityService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private WkflTaskService wkflTaskService;

    @Autowired
    private WorkflowService workflowService;

    @Autowired
    private RepositoryService repositoryService;

    /**
     * 启动
     *
     * @param processDefKey
     * @return
     */
    @Transactional
    @GetMapping("/start/{processDefKey}")
    public Result<String> start(@PathVariable("processDefKey") String processDefKey) {
        //便于在流程对象中记录发起人
        identityService.setAuthenticatedUserId("admin");
        VariableMap variables = Variables.createVariables();
        String businessKey = processDefKey + ":" + IdWorker.getMillisecond();
        OperationVo operationVo = new OperationVo();
        operationVo.setOperationType("start");
        operationVoHolder.set(operationVo);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefKey, businessKey, variables);
        return Result.ok(processInstance.getProcessInstanceId()).message("启动成功");
    }

    /**
     * 提交
     *
     * @param taskId
     * @return
     */
    @Transactional
    @GetMapping("/commit/{taskId}")
    public Result commit(@PathVariable("taskId") String taskId) {
        //存在未完成的反馈意见任务,不可提交
        boolean exist = workflowService.existUnfinishedFeedbackTasks(taskId);
        if (exist) {
            return Result.fail().message("您正在征求他人意见，不可提交");
        }

        //完成自己的任务,设置完成时间，完成类型
        WkflTaskEntity wkflTaskEntity = wkflTaskService.getById(taskId);
        wkflTaskEntity.setFinishTime(new Date());
        wkflTaskEntity.setFinishType("approved");
        wkflTaskEntity.setPhaseOpinion("审批通过");
        wkflTaskService.updateById(wkflTaskEntity);

        //删除同级多余的待办(完成时间为空)
        LambdaQueryWrapper<WkflTaskEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WkflTaskEntity::getRealTaskId, wkflTaskEntity.getRealTaskId());
        queryWrapper.ne(WkflTaskEntity::getId, taskId);
        queryWrapper.isNull(WkflTaskEntity::getFinishTime);
        List<WkflTaskEntity> others = wkflTaskService.list(queryWrapper);
        wkflTaskService.removeBatchByIds(others);
        //以及自动转授权的记录
        for (WkflTaskEntity other : others) {
            WkflTaskEntity tempTask = other;
            while (tempTask != null) {
                LambdaQueryWrapper<WkflTaskEntity> queryBeforeEntrusted = new LambdaQueryWrapper<>();
                queryBeforeEntrusted.eq(WkflTaskEntity::getId, tempTask.getSrcId());
                queryBeforeEntrusted.eq(WkflTaskEntity::getFinishType, "entrusted");
                queryBeforeEntrusted.eq(WkflTaskEntity::getTaskDefKey, tempTask.getTaskDefKey());
                WkflTaskEntity beforeEntrusted = wkflTaskService.getOne(queryBeforeEntrusted);
                tempTask = beforeEntrusted;
                if (beforeEntrusted != null) {
                    wkflTaskService.removeById(beforeEntrusted);
                }
            }
        }

        //判断任务，是否要提交到导师
        //TODO Call remote to fetch tutor，zhangsan导师tutor666
        String tutorId = "zhangsan".equals(wkflTaskEntity.getAssignee()) ? "tutor666" : "";
        if (StringUtils.isBlank(tutorId)) {
            //无导师，让流程正常提交，生成的新任务，由监听器处理
            OperationVo operationVo = new OperationVo();
            operationVo.setOperationType("commit");
            operationVo.setTaskId(taskId);
            operationVoHolder.set(operationVo);

            String targetKey = (String) runtimeService.getVariable(wkflTaskEntity.getProcInstId(), wkflTaskEntity.getTaskDefKey());
            if (StringUtils.isNotBlank(targetKey)) {
                //退回的任务，走跳转
                runtimeService.createProcessInstanceModification(wkflTaskEntity.getProcInstId())
                        .cancelAllForActivity(wkflTaskEntity.getTaskDefKey()) // 取消当前节点所有活动中的Task任务
                        .startBeforeActivity(targetKey) // 目标节点Id，在流程图中看，固定值（一般起一个正规的名字）
                        .setVariable("带入所需变量key", "变量值Object类型")
                        .setAnnotation("jump提交") // 为当前实例的修改添加注释，虽然没有实际业务作用，但是推荐使用
                        .execute();
                runtimeService.removeVariable(wkflTaskEntity.getProcInstId(), wkflTaskEntity.getTaskDefKey());
            } else {
                //正常提交
                taskService.complete(wkflTaskEntity.getRealTaskId());
            }
        } else {
            //有导师，生成导师任务
            WkflTaskEntity tutorTask = new WkflTaskEntity();
            BeanUtils.copyProperties(wkflTaskEntity, tutorTask);
            tutorTask.setId(null);
            tutorTask.setSrcId(wkflTaskEntity.getId());
            tutorTask.setCreateTime(new Date());
            tutorTask.setFinishTime(null);
            tutorTask.setFinishType(null);
            tutorTask.setPhaseOpinion(null);
            tutorTask.setName(wkflTaskEntity.getName() + "导师");
            tutorTask.setAssignee(tutorId);
            wkflTaskService.save(tutorTask);

            //导师转授权
            workflowService.autoEntrust(tutorTask);
        }

        return Result.ok().message("提交成功");
    }

    /**
     * 转他人处理
     */
    @Transactional
    @GetMapping("/transferTo/{taskId}/{toUserId}")
    public Result transferTo(@PathVariable("taskId") String taskId,
                             @PathVariable("toUserId") String toUserId) {
        //完成旧任务
        WkflTaskEntity wkflTaskEntity = wkflTaskService.getById(taskId);
        wkflTaskEntity.setFinishTime(new Date());
        wkflTaskEntity.setFinishType("transfered");
        wkflTaskEntity.setPhaseOpinion(wkflTaskEntity.getAssignee() + "转" + toUserId + "处理");
        wkflTaskService.updateById(wkflTaskEntity);

        //删除同级多余的待办(完成时间为空)
        LambdaQueryWrapper<WkflTaskEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WkflTaskEntity::getRealTaskId, wkflTaskEntity.getRealTaskId());
        queryWrapper.ne(WkflTaskEntity::getId, taskId);
        queryWrapper.isNull(WkflTaskEntity::getFinishTime);
        List<WkflTaskEntity> others = wkflTaskService.list(queryWrapper);
        wkflTaskService.removeBatchByIds(others);
        //以及自动转授权的记录
        for (WkflTaskEntity other : others) {
            WkflTaskEntity tempTask = other;
            while (tempTask != null) {
                LambdaQueryWrapper<WkflTaskEntity> queryBeforeEntrusted = new LambdaQueryWrapper<>();
                queryBeforeEntrusted.eq(WkflTaskEntity::getId, tempTask.getSrcId());
                queryBeforeEntrusted.eq(WkflTaskEntity::getFinishType, "entrusted");
                queryBeforeEntrusted.eq(WkflTaskEntity::getTaskDefKey, tempTask.getTaskDefKey());
                WkflTaskEntity beforeEntrusted = wkflTaskService.getOne(queryBeforeEntrusted);
                tempTask = beforeEntrusted;
                if (beforeEntrusted != null) {
                    wkflTaskService.removeById(beforeEntrusted);
                }
            }
        }

        //生成新任务
        WkflTaskEntity toTaskEntity = new WkflTaskEntity();
        BeanUtils.copyProperties(wkflTaskEntity, toTaskEntity);
        toTaskEntity.setId(null);
        toTaskEntity.setSrcId(taskId);
        toTaskEntity.setAssignee(toUserId);
        toTaskEntity.setCreateTime(new Date());
        toTaskEntity.setFinishTime(null);
        toTaskEntity.setFinishType(null);
        toTaskEntity.setPhaseOpinion(null);
        wkflTaskService.save(toTaskEntity);

        //转他人处理的任务，自动转授权
        workflowService.autoEntrust(toTaskEntity);

        return Result.ok().message("转他人处理成功");
    }

    /**
     * 否决
     *
     * @param taskId
     * @return
     */
    @Transactional
    @GetMapping("/reject/{taskId}")
    public Result reject(@PathVariable("taskId") String taskId) {
        //TODO 挂起的流程，不可以否决
        OperationVo operationVo = new OperationVo();
        operationVo.setOperationType("reject");
        operationVo.setTaskId(taskId);
        operationVoHolder.set(operationVo);

        //否决当前任务
        WkflTaskEntity taskEntity = wkflTaskService.getById(taskId);
        taskEntity.setFinishTime(new Date());
        taskEntity.setFinishType("rejected");
        taskEntity.setPhaseOpinion("已否决");
        wkflTaskService.updateById(taskEntity);

        //删除同级多余的待办(完成时间为空)
        LambdaQueryWrapper<WkflTaskEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WkflTaskEntity::getRealTaskId, taskEntity.getRealTaskId());
        queryWrapper.ne(WkflTaskEntity::getId, taskId);
        queryWrapper.isNull(WkflTaskEntity::getFinishTime);
        List<WkflTaskEntity> others = wkflTaskService.list(queryWrapper);
        wkflTaskService.removeBatchByIds(others);
        //以及自动转授权的记录
        for (WkflTaskEntity other : others) {
            WkflTaskEntity tempTask = other;
            while (tempTask != null) {
                LambdaQueryWrapper<WkflTaskEntity> queryBeforeEntrusted = new LambdaQueryWrapper<>();
                queryBeforeEntrusted.eq(WkflTaskEntity::getId, tempTask.getSrcId());
                queryBeforeEntrusted.eq(WkflTaskEntity::getFinishType, "entrusted");
                queryBeforeEntrusted.eq(WkflTaskEntity::getTaskDefKey, tempTask.getTaskDefKey());
                WkflTaskEntity beforeEntrusted = wkflTaskService.getOne(queryBeforeEntrusted);
                tempTask = beforeEntrusted;
                if (beforeEntrusted != null) {
                    wkflTaskService.removeById(beforeEntrusted);
                }
            }
        }

        //生成一条流程结束的任务
        WkflTaskEntity finishTask = new WkflTaskEntity();
        finishTask.setCreateTime(new Date());
        finishTask.setFinishTime(new Date());
        finishTask.setName("流程结束标记");
        finishTask.setAssignee("system");
        finishTask.setPhaseOpinion("流程已结束");
        finishTask.setSrcId(taskEntity.getId());
        finishTask.setFinishType("finished");
        finishTask.setTenantId(taskEntity.getTenantId());
        finishTask.setProcInstId(taskEntity.getProcInstId());
        wkflTaskService.save(finishTask);

        //找到结束节点
        BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(taskEntity.getProcDefId());
        List<DomElement> childElements = bpmnModelInstance.getDocument().getRootElement().getChildElements();
        DomElement domElement = childElements.stream().filter(it -> "process".equals(it.getLocalName())).findFirst().orElse(null);
        List<String> endActivitiIds = domElement.getChildElements().stream()
                .filter(it -> "endEvent".equals(it.getLocalName()))
                .map(it -> (it.getAttribute("id")))
                .collect(Collectors.toList());

        //控制流程
        runtimeService.createProcessInstanceModification(taskEntity.getProcInstId())
                .cancelAllForActivity(taskEntity.getTaskDefKey()) // 取消当前节点所有活动中的Task任务
                .startBeforeActivity(endActivitiIds.get(0)) // 目标节点Id，在流程图中看，固定值（一般起一个正规的名字）
                .setVariable("带入所需变量key", "变量值Object类型")
                .setAnnotation("否决跳转") // 为当前实例的修改添加注释，虽然没有实际业务作用，但是推荐使用
                .execute();

        return Result.ok().message("否决成功");
    }

    /**
     * 驳回
     *
     * @return
     */
    @Transactional
    @GetMapping("/rejectBack/{taskId}/{targetTaskId}")
    public Result rejectBack(@PathVariable("taskId") String taskId,
                             @PathVariable("targetTaskId") String targetTaskId) {
        //取出目标节点key
        WkflTaskEntity targetTask = wkflTaskService.getById(targetTaskId);
        String targetKey = targetTask.getTaskDefKey();

        //先完成驳回的任务
        WkflTaskEntity taskEntity = wkflTaskService.getById(taskId);
        taskEntity.setFinishTime(new Date());
        taskEntity.setFinishType("rejectBacked");
        taskEntity.setPhaseOpinion("驳回到" + targetTask.getName() + targetTask.getAssignee() + "处理");
        wkflTaskService.updateById(taskEntity);

        //删除同级多余的待办(完成时间为空)
        LambdaQueryWrapper<WkflTaskEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WkflTaskEntity::getRealTaskId, taskEntity.getRealTaskId());
        queryWrapper.ne(WkflTaskEntity::getId, taskId);
        queryWrapper.isNull(WkflTaskEntity::getFinishTime);
        List<WkflTaskEntity> others = wkflTaskService.list(queryWrapper);
        wkflTaskService.removeBatchByIds(others);
        //以及自动转授权的记录
        for (WkflTaskEntity other : others) {
            WkflTaskEntity tempTask = other;
            while (tempTask != null) {
                LambdaQueryWrapper<WkflTaskEntity> queryBeforeEntrusted = new LambdaQueryWrapper<>();
                queryBeforeEntrusted.eq(WkflTaskEntity::getId, tempTask.getSrcId());
                queryBeforeEntrusted.eq(WkflTaskEntity::getFinishType, "entrusted");
                queryBeforeEntrusted.eq(WkflTaskEntity::getTaskDefKey, tempTask.getTaskDefKey());
                WkflTaskEntity beforeEntrusted = wkflTaskService.getOne(queryBeforeEntrusted);
                tempTask = beforeEntrusted;
                if (beforeEntrusted != null) {
                    wkflTaskService.removeById(beforeEntrusted);
                }
            }
        }

        //驳回的目标任务是带有处理人的
        OperationVo operationVo = new OperationVo();
        operationVo.setOperationType("rejectBack");
        operationVo.setTaskId(taskId);
        operationVo.setTargetTaskId(targetTaskId);
        operationVoHolder.set(operationVo);

        //控制流程
        runtimeService.createProcessInstanceModification(taskEntity.getProcInstId())
                .cancelAllForActivity(taskEntity.getTaskDefKey()) // 取消当前节点所有活动中的Task任务
                .startBeforeActivity(targetKey) // 目标节点Id，在流程图中看，固定值（一般起一个正规的名字）
                .setVariable("带入所需变量key", "变量值Object类型")
                .setAnnotation("驳回跳转") // 为当前实例的修改添加注释，虽然没有实际业务作用，但是推荐使用
                .execute();

        return Result.ok().message("驳回成功");
    }

    @GetMapping("/getAllowedBackHistoryTasks/{taskId}")
    public Result<List<WkflTaskEntity>> getAllowedBackHistoryTasks(@PathVariable("taskId") String taskId) {
        WkflTaskEntity fromTask = wkflTaskService.getById(taskId);
        String fromTaskKey = fromTask.getTaskDefKey();
        BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(fromTask.getProcDefId());
        FlowNode fromNode = bpmnModelInstance.getModelElementById(fromTaskKey);
        Set<String> allowedKeys = new HashSet<>();
        workflowService.getAllowedBackTaskDefKeys(allowedKeys, fromNode, bpmnModelInstance);
        List<WkflTaskEntity> allowedBackTasks = new ArrayList<>();

        //本节点，仅限导师退回驳回普通任务
        LambdaQueryWrapper<WkflTaskEntity> queryTutorTasksInSameNodeWrapper = new LambdaQueryWrapper();
        queryTutorTasksInSameNodeWrapper.eq(WkflTaskEntity::getProcInstId, fromTask.getProcInstId());
        queryTutorTasksInSameNodeWrapper.eq(WkflTaskEntity::getTaskDefKey, fromTaskKey);
        queryTutorTasksInSameNodeWrapper.like(WkflTaskEntity::getName, "导师");
        queryTutorTasksInSameNodeWrapper.isNotNull(WkflTaskEntity::getFinishTime);
        queryTutorTasksInSameNodeWrapper.orderByDesc(WkflTaskEntity::getFinishTime);
        List<WkflTaskEntity> tutorTasksInSameNode = wkflTaskService.list(queryTutorTasksInSameNodeWrapper);
        if (!CollectionUtils.isEmpty(tutorTasksInSameNode)) {
            //有导师，再去寻找普通任务
            LambdaQueryWrapper<WkflTaskEntity> queryCommonTaskInSameNodeWrapper = new LambdaQueryWrapper();
            queryCommonTaskInSameNodeWrapper.eq(WkflTaskEntity::getProcInstId, fromTask.getProcInstId());
            queryCommonTaskInSameNodeWrapper.eq(WkflTaskEntity::getTaskDefKey, fromTaskKey);
            queryCommonTaskInSameNodeWrapper.notLike(WkflTaskEntity::getName, "导师");
            queryCommonTaskInSameNodeWrapper.isNotNull(WkflTaskEntity::getFinishTime);
            queryCommonTaskInSameNodeWrapper.orderByDesc(WkflTaskEntity::getFinishTime);
            List<WkflTaskEntity> commonTasksInSameNode = wkflTaskService.list(queryCommonTaskInSameNodeWrapper);
            if (!CollectionUtils.isEmpty(commonTasksInSameNode)) {
                allowedBackTasks.add(0, commonTasksInSameNode.get(0));
            }
        }

        //非本节点，同时寻找导师和普通任务
        for (String allowedKey : allowedKeys) {
            //寻找节点内的导师任务
            LambdaQueryWrapper<WkflTaskEntity> queryTutorTasksInOtherNodeWrapper = new LambdaQueryWrapper();
            queryTutorTasksInOtherNodeWrapper.eq(WkflTaskEntity::getProcInstId, fromTask.getProcInstId());
            queryTutorTasksInOtherNodeWrapper.eq(WkflTaskEntity::getTaskDefKey, allowedKey);
            queryTutorTasksInOtherNodeWrapper.like(WkflTaskEntity::getName, "导师");
            queryTutorTasksInOtherNodeWrapper.isNotNull(WkflTaskEntity::getFinishTime);
            queryTutorTasksInOtherNodeWrapper.orderByDesc(WkflTaskEntity::getFinishTime);
            List<WkflTaskEntity> tutorTasksInOtherNode = wkflTaskService.list(queryTutorTasksInOtherNodeWrapper);
            if (!CollectionUtils.isEmpty(tutorTasksInOtherNode)) {
                allowedBackTasks.add(0, tutorTasksInOtherNode.get(0));
            }
            //寻找节点内的普通任务
            LambdaQueryWrapper<WkflTaskEntity> queryCommonTaskInOtherNodeWrapper = new LambdaQueryWrapper();
            queryCommonTaskInOtherNodeWrapper.eq(WkflTaskEntity::getProcInstId, fromTask.getProcInstId());
            queryCommonTaskInOtherNodeWrapper.eq(WkflTaskEntity::getTaskDefKey, allowedKey);
            queryCommonTaskInOtherNodeWrapper.notLike(WkflTaskEntity::getName, "导师");
            queryCommonTaskInOtherNodeWrapper.isNotNull(WkflTaskEntity::getFinishTime);
            queryCommonTaskInOtherNodeWrapper.orderByDesc(WkflTaskEntity::getFinishTime);
            List<WkflTaskEntity> commonTasksInOtherNode = wkflTaskService.list(queryCommonTaskInOtherNodeWrapper);
            if (!CollectionUtils.isEmpty(commonTasksInOtherNode)) {
                allowedBackTasks.add(0, commonTasksInOtherNode.get(0));
            }
        }
        return Result.ok(allowedBackTasks).message("成功获取可退回的任务列表");
    }

    /**
     * 退回
     *
     * @return
     */
    @Transactional
    @GetMapping("/pointBack/{taskId}/{targetTaskId}")
    public Result pointBack(@PathVariable("taskId") String taskId,
                            @PathVariable("targetTaskId") String targetTaskId) {

        //取出目标节点key
        WkflTaskEntity targetTask = wkflTaskService.getById(targetTaskId);
        String targetKey = targetTask.getTaskDefKey();

        //先完成驳回的任务
        WkflTaskEntity taskEntity = wkflTaskService.getById(taskId);
        taskEntity.setFinishTime(new Date());
        taskEntity.setFinishType("pointBacked");
        taskEntity.setPhaseOpinion("退回到" + targetTask.getName() + targetTask.getAssignee() + "处理");
        wkflTaskService.updateById(taskEntity);

        //删除同级多余的待办(完成时间为空)
        LambdaQueryWrapper<WkflTaskEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WkflTaskEntity::getRealTaskId, taskEntity.getRealTaskId());
        queryWrapper.ne(WkflTaskEntity::getId, taskId);
        queryWrapper.isNull(WkflTaskEntity::getFinishTime);
        List<WkflTaskEntity> others = wkflTaskService.list(queryWrapper);
        wkflTaskService.removeBatchByIds(others);
        //以及自动转授权的记录
        for (WkflTaskEntity other : others) {
            WkflTaskEntity tempTask = other;
            while (tempTask != null) {
                LambdaQueryWrapper<WkflTaskEntity> queryBeforeEntrusted = new LambdaQueryWrapper<>();
                queryBeforeEntrusted.eq(WkflTaskEntity::getId, tempTask.getSrcId());
                queryBeforeEntrusted.eq(WkflTaskEntity::getFinishType, "entrusted");
                queryBeforeEntrusted.eq(WkflTaskEntity::getTaskDefKey, tempTask.getTaskDefKey());
                WkflTaskEntity beforeEntrusted = wkflTaskService.getOne(queryBeforeEntrusted);
                tempTask = beforeEntrusted;
                if (beforeEntrusted != null) {
                    wkflTaskService.removeById(beforeEntrusted);
                }
            }
        }

        //驳回的目标任务是带有处理人的
        OperationVo operationVo = new OperationVo();
        operationVo.setOperationType("pointBack");
        operationVo.setTaskId(taskId);
        operationVo.setTargetTaskId(targetTaskId);
        operationVoHolder.set(operationVo);

        //控制流程
        runtimeService.createProcessInstanceModification(taskEntity.getProcInstId())
                .cancelAllForActivity(taskEntity.getTaskDefKey()) // 取消当前节点所有活动中的Task任务
                .startBeforeActivity(targetKey) // 目标节点Id，在流程图中看，固定值（一般起一个正规的名字）
                .setVariable(targetKey, taskEntity.getTaskDefKey())
                .setAnnotation("驳回跳转") // 为当前实例的修改添加注释，虽然没有实际业务作用，但是推荐使用
                .execute();

        return Result.ok().message("退回成功");
    }

    /**
     * 征求他人意见
     *
     * @return
     */
    @Transactional
    @PostMapping("/takeAdvice/{taskId}")
    public Result takeAdvice(@PathVariable("taskId") String taskId,
                             @RequestBody Set<String> toUserIds) {

        //当前任务,是否首次征求意见
        boolean isFirstTakeAdvice = true;
        WkflTaskEntity taskEntity = wkflTaskService.getById(taskId);
        LambdaQueryWrapper<WkflTaskEntity> queryTakeAdviceActions = new LambdaQueryWrapper<>();
        queryTakeAdviceActions.eq(WkflTaskEntity::getSrcId, taskId);
        queryTakeAdviceActions.eq(WkflTaskEntity::getFinishType, "takeAdvice");
        List<WkflTaskEntity> takeAdviceActions = wkflTaskService.list(queryTakeAdviceActions);
        if (!CollectionUtils.isEmpty(takeAdviceActions)) {
            isFirstTakeAdvice = false;
        }

        if (isFirstTakeAdvice) {
            //首次需删除协同的待办
            LambdaQueryWrapper<WkflTaskEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(WkflTaskEntity::getRealTaskId, taskEntity.getRealTaskId());
            queryWrapper.ne(WkflTaskEntity::getId, taskId);
            queryWrapper.isNull(WkflTaskEntity::getFinishTime);
            List<WkflTaskEntity> others = wkflTaskService.list(queryWrapper);
            wkflTaskService.removeBatchByIds(others);
            //以及自动转授权的记录
            for (WkflTaskEntity other : others) {
                WkflTaskEntity tempTask = other;
                while (tempTask != null) {
                    LambdaQueryWrapper<WkflTaskEntity> queryBeforeEntrusted = new LambdaQueryWrapper<>();
                    queryBeforeEntrusted.eq(WkflTaskEntity::getId, tempTask.getSrcId());
                    queryBeforeEntrusted.eq(WkflTaskEntity::getFinishType, "entrusted");
                    queryBeforeEntrusted.eq(WkflTaskEntity::getTaskDefKey, tempTask.getTaskDefKey());
                    WkflTaskEntity beforeEntrusted = wkflTaskService.getOne(queryBeforeEntrusted);
                    tempTask = beforeEntrusted;
                    if (beforeEntrusted != null) {
                        wkflTaskService.removeById(beforeEntrusted);
                    }
                }
            }

            //生成征求意见动作
            WkflTaskEntity takeAdviceAction = new WkflTaskEntity();
            BeanUtils.copyProperties(taskEntity, takeAdviceAction);
            takeAdviceAction.setId(null);
            takeAdviceAction.setSrcId(taskId);
            takeAdviceAction.setName(taskEntity.getName() + "[征求意见]");
            takeAdviceAction.setCreateTime(new Date());
            takeAdviceAction.setFinishTime(new Date());
            takeAdviceAction.setFinishType("takeAdvice");
            takeAdviceAction.setPhaseOpinion(taskEntity.getAssignee() + "征求" + toUserIds + "意见");
            wkflTaskService.save(takeAdviceAction);

            //生成反馈意见
            for (String toUserId : toUserIds) {
                WkflTaskEntity feedbackTask = new WkflTaskEntity();
                BeanUtils.copyProperties(takeAdviceAction, feedbackTask);
                feedbackTask.setId(null);
                feedbackTask.setSrcId(takeAdviceAction.getId());
                feedbackTask.setAssignee(toUserId);
                feedbackTask.setCreateTime(new Date());
                feedbackTask.setFinishTime(null);
                feedbackTask.setFinishType(null);
                feedbackTask.setPhaseOpinion(null);
                wkflTaskService.save(feedbackTask);
                workflowService.autoEntrust(feedbackTask);
            }
        } else {
            //非首次，收回或追加征求意见
            //查出takeAdviceAction
            LambdaQueryWrapper<WkflTaskEntity> queryTakeAdviceAction = new LambdaQueryWrapper<>();
            queryTakeAdviceAction.eq(WkflTaskEntity::getSrcId, taskEntity.getId());
            queryTakeAdviceAction.like(WkflTaskEntity::getName, "[征求意见]");
            WkflTaskEntity takeAdviceAction = wkflTaskService.getOne(queryTakeAdviceAction);
            //查询出当前未完成的征求意见
            List<WkflTaskEntity> unfinishedFeedbackTasks = workflowService.queryUnfinishedFeedbackTasks(taskId);
            Set<String> unfinishedUserIds = unfinishedFeedbackTasks.stream().map(WkflTaskEntity::getAssignee).collect(Collectors.toSet());
            for (String toUserId : toUserIds) {
                if (!unfinishedUserIds.contains(toUserId)) {
                    //追加
                    WkflTaskEntity feedbackTask = new WkflTaskEntity();
                    BeanUtils.copyProperties(takeAdviceAction, feedbackTask);
                    feedbackTask.setId(null);
                    feedbackTask.setSrcId(takeAdviceAction.getId());
                    feedbackTask.setAssignee(toUserId);
                    feedbackTask.setCreateTime(new Date());
                    feedbackTask.setFinishTime(null);
                    feedbackTask.setFinishType(null);
                    feedbackTask.setPhaseOpinion(null);
                    wkflTaskService.save(feedbackTask);
                    workflowService.autoEntrust(feedbackTask);
                }
            }
            for (String unfinishedUserId : unfinishedUserIds) {
                if (!toUserIds.contains(unfinishedUserId)) {
                    //收回
                    List<WkflTaskEntity> unfinishedTasks = unfinishedFeedbackTasks
                            .stream()
                            .filter(task -> unfinishedUserId.equals(task.getAssignee()))
                            .collect(Collectors.toList());
                    for (WkflTaskEntity unfinishedTask : unfinishedTasks) {
                        unfinishedTask.setFinishTime(new Date());
                        unfinishedTask.setFinishType("takeAdviceRetrieve");
                        unfinishedTask.setPhaseOpinion("征求意见收回");
                        wkflTaskService.updateById(unfinishedTask);
                    }
                }
            }
        }

        return Result.ok().message("征求他人意见成功" + toUserIds);
    }

    @Transactional
    @PostMapping("/feedback/{taskId}/{comment}")
    public Result feedback(@PathVariable("taskId") String taskId,
                           @PathVariable("comment") String comment) {

        WkflTaskEntity wkflTaskEntity = wkflTaskService.getById(taskId);
        //判断反馈意见，是否要过导师
        //TODO Call remote to fetch tutor，zhangsan导师tutor666
        String tutorId = "zhangsan".equals(wkflTaskEntity.getAssignee()) ? "tutor666" : "";
        if (StringUtils.isBlank(tutorId)) {
            //无导师
            wkflTaskEntity.setFinishTime(new Date());
            wkflTaskEntity.setFinishType("feedbacked");
            wkflTaskEntity.setDescription(comment);
            wkflTaskEntity.setPhaseOpinion("已反馈意见");
            wkflTaskService.updateById(wkflTaskEntity);
            return Result.ok().message("反馈意见成功");
        } else {
            //有导师
            wkflTaskEntity.setFinishTime(new Date());
            wkflTaskEntity.setFinishType("feedbackToTutor");
            wkflTaskEntity.setDescription(comment);
            wkflTaskEntity.setPhaseOpinion("反馈意见过导师:" + tutorId);
            wkflTaskService.updateById(wkflTaskEntity);

            //生成导师任务
            WkflTaskEntity tutorTask = new WkflTaskEntity();
            BeanUtils.copyProperties(wkflTaskEntity, tutorTask);
            tutorTask.setId(null);
            tutorTask.setSrcId(wkflTaskEntity.getId());
            tutorTask.setAssignee(tutorId);
            tutorTask.setCreateTime(new Date());
            tutorTask.setFinishTime(null);
            tutorTask.setFinishType(null);
            tutorTask.setPhaseOpinion(null);
            wkflTaskService.save(tutorTask);
            workflowService.autoEntrust(tutorTask);
            return Result.ok().message("反馈意见过导师:" + tutorId);
        }
    }

    /**
     * 传阅
     *
     * @return
     */
    @Transactional
    @PostMapping("/fyi/{taskId}")
    public Result fyi(@PathVariable("taskId") String taskId,
                      @RequestBody Set<String> toUserIds) {
        WkflTaskEntity taskEntity = wkflTaskService.getById(taskId);
        //首次需删除协同的待办
        LambdaQueryWrapper<WkflTaskEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WkflTaskEntity::getRealTaskId, taskEntity.getRealTaskId());
        queryWrapper.ne(WkflTaskEntity::getId, taskId);
        queryWrapper.isNull(WkflTaskEntity::getFinishTime);
        List<WkflTaskEntity> others = wkflTaskService.list(queryWrapper);
        wkflTaskService.removeBatchByIds(others);
        //以及自动转授权的记录
        for (WkflTaskEntity other : others) {
            WkflTaskEntity tempTask = other;
            while (tempTask != null) {
                LambdaQueryWrapper<WkflTaskEntity> queryBeforeEntrusted = new LambdaQueryWrapper<>();
                queryBeforeEntrusted.eq(WkflTaskEntity::getId, tempTask.getSrcId());
                queryBeforeEntrusted.eq(WkflTaskEntity::getFinishType, "entrusted");
                queryBeforeEntrusted.eq(WkflTaskEntity::getTaskDefKey, tempTask.getTaskDefKey());
                WkflTaskEntity beforeEntrusted = wkflTaskService.getOne(queryBeforeEntrusted);
                tempTask = beforeEntrusted;
                if (beforeEntrusted != null) {
                    wkflTaskService.removeById(beforeEntrusted);
                }
            }
        }

        for (String toUserId : toUserIds) {
            WkflTaskEntity fyiTask = new WkflTaskEntity();
            BeanUtils.copyProperties(taskEntity, fyiTask);
            fyiTask.setId(null);
            fyiTask.setSrcId(taskEntity.getId());
            fyiTask.setAssignee(toUserId);
            fyiTask.setCreateTime(new Date());
            fyiTask.setFinishTime(new Date());
            fyiTask.setFinishType("fyi");
            fyiTask.setPhaseOpinion(taskEntity.getAssignee() + "传阅给" + toUserId);
            fyiTask.setName(taskEntity.getName() + "[传阅]");
            wkflTaskService.save(fyiTask);
        }

        return Result.ok().message("传阅成功");
    }

    /**
     * 撤回
     *
     * @return
     */
    @Transactional
    @GetMapping("/retrieve/{taskId}")
    public Result retrieve(@PathVariable("taskId") String taskId) {

        WkflTaskEntity taskEntity = wkflTaskService.getById(taskId);
        if (taskEntity == null) {
            return Result.fail().message("任务不存在");
        }
        if (taskEntity.getFinishTime() == null) {
            return Result.fail().message("待办，不可撤回");
        }
        if (!"approved".equals(taskEntity.getFinishType())) {
            return Result.fail().message("非approved类型，不可撤回");
        }

        //找出下一岗
        LambdaQueryWrapper<WkflTaskEntity> queryNextTasks = new LambdaQueryWrapper<>();
        queryNextTasks.eq(WkflTaskEntity::getSrcId, taskEntity.getId());
        List<WkflTaskEntity> nextTasks = wkflTaskService.list(queryNextTasks);

        //根据下一岗是否操作过，判断能否撤回
        for (WkflTaskEntity nextTask : nextTasks) {
            WkflTaskEntity tempTask = nextTask;
            //找到非转授权的任务
            while ("entrusted".equals(tempTask.getFinishType())) {
                LambdaQueryWrapper<WkflTaskEntity> queryNextTask = new LambdaQueryWrapper<>();
                queryNextTask.eq(WkflTaskEntity::getSrcId, tempTask.getId());
                tempTask = wkflTaskService.getOne(queryNextTask);
            }
            //找到了非转授权的任务
            if (tempTask.getFinishTime() != null) {
                return Result.fail().message("撤回失败，下一岗" + tempTask.getName() + "已于" + tempTask.getFinishTime() + "处理任务");
            }
            //征求意见
            LambdaQueryWrapper<WkflTaskEntity> queryTakeAdvice = new LambdaQueryWrapper<>();
            queryTakeAdvice.eq(WkflTaskEntity::getSrcId, tempTask.getId());
            queryTakeAdvice.eq(WkflTaskEntity::getFinishType, "takeAdvice");
            WkflTaskEntity takeAdviceTask = wkflTaskService.getOne(queryTakeAdvice);
            if (takeAdviceTask != null) {
                return Result.fail().message("撤回失败，下一岗" + tempTask.getName() + "已于" + takeAdviceTask.getFinishTime() + "征求意见");
            }
            //传阅
            LambdaQueryWrapper<WkflTaskEntity> queryFyi = new LambdaQueryWrapper<>();
            queryFyi.eq(WkflTaskEntity::getSrcId, tempTask.getId());
            queryFyi.eq(WkflTaskEntity::getFinishType, "fyi");
            queryFyi.orderByDesc(WkflTaskEntity::getFinishTime);
            List<WkflTaskEntity> fyiTasks = wkflTaskService.list(queryFyi);
            if (!CollectionUtils.isEmpty(fyiTasks)) {
                return Result.fail().message("撤回失败，下一岗" + tempTask.getName() + "已于" + fyiTasks.get(0).getFinishTime() + "传阅");
            }
        }

        //开始撤回
        List<Task> currentAliveTask = taskService.createTaskQuery().processInstanceId(taskEntity.getProcInstId()).list();
        Set<String> currentAliveNodeKeys = currentAliveTask.stream().map(Task::getTaskDefinitionKey).collect(Collectors.toSet());

        //新增撤回的操作记录
        WkflTaskEntity doRetrieve = new WkflTaskEntity();
        BeanUtils.copyProperties(taskEntity, doRetrieve);
        doRetrieve.setId(null);
        doRetrieve.setSrcId(taskEntity.getId());
        doRetrieve.setCreateTime(new Date());
        doRetrieve.setFinishTime(new Date());
        doRetrieve.setFinishType("doRetrieve");
        doRetrieve.setPhaseOpinion("发起撤回");
        wkflTaskService.save(doRetrieve);

        //考虑转授权
        for (WkflTaskEntity nextTask : nextTasks) {
            WkflTaskEntity tempTask = nextTask;
            while ("entrusted".equals(tempTask.getFinishType())) {
                LambdaQueryWrapper<WkflTaskEntity> queryNextTask = new LambdaQueryWrapper<>();
                queryNextTask.eq(WkflTaskEntity::getSrcId, tempTask.getId());
                tempTask = wkflTaskService.getOne(queryNextTask);
            }
            tempTask.setFinishTime(new Date());
            tempTask.setFinishType("retrieved");
            tempTask.setPhaseOpinion("待办被" + taskEntity.getName() + "撤回");
            wkflTaskService.updateById(tempTask);
        }

        //控制流程
        OperationVo operationVo = new OperationVo();
        operationVo.setTaskId(taskId);
        operationVo.setOperationType("doRetrieve");
        operationVoHolder.set(operationVo);
        ProcessInstanceModificationBuilder processInstanceModification = runtimeService.createProcessInstanceModification(taskEntity.getProcInstId());
        for (String currentAliveNodeKey : currentAliveNodeKeys) {
            processInstanceModification.cancelAllForActivity(currentAliveNodeKey);
        }
        processInstanceModification
                .startBeforeActivity(taskEntity.getTaskDefKey()) // 目标节点Id，在流程图中看，固定值（一般起一个正规的名字）
                .setAnnotation("撤回跳转") // 为当前实例的修改添加注释，虽然没有实际业务作用，但是推荐使用
                .execute();

        return Result.ok().message("撤回成功");
    }

    @Transactional
    @PostMapping("/deploy")
    public Result deploy(@RequestPart("file") MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        InputStream inputStream = file.getInputStream();
        // 1. 构建部署对象
        Deployment deployment = repositoryService
                .createDeployment()
                .name(originalFilename)
                .source("Web")
                .addInputStream(originalFilename, inputStream)
                .deploy();
        inputStream.close();
        return Result.ok("deploymentId:" + deployment.getId()).message("部署成功");
    }
}
